﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace QbiconEditor
{
    public class QStandartRender : IQRender
    {
        public QPreferences Preferences
        {
            get
            {
                return QGraphicsHelper.Preferences;
            }
        }

        public float ZoomAspect
        {
            get
            {
                return QGraphicsHelper.ZoomAspect;
            }
        }

        public QImageList Textures
        {
            get
            {
                return QGraphicsHelper.Textures;
            }
        }

        public QRectangleF ViewRect
        {
            get
            {
                return QGraphicsHelper.ViewRect;
            }
        }

        public void RenderMap(QMap map, Graphics graph, List<QMapLayer> exceptLayers, List<QObject> exceptObjects, bool useTextures, bool drawPoints)
        {
          if (graph == null || map == null)
          {
            return;
          }

          graph.Clear(map.BackgroundColor);
          RenderLayers(map.Layers, graph, exceptLayers, exceptObjects, useTextures, drawPoints);
        }

        public void RenderLayers(List<QMapLayer> layers, Graphics graph, List<QMapLayer> exceptLayers, List<QObject> exceptObjects, bool useTextures, bool drawPoints)
        {
          if (layers != null)
          {
            foreach (QMapLayer layer in layers)
            {
              RenderLayer(layer, graph, exceptObjects, useTextures, drawPoints);
            }
          }
        }

        public void RenderLayer(QMapLayer layer, Graphics graph, List<QObject> exceptObjects, bool useTextures, bool drawPoints)
        {
          if (layer != null)
          {
            if (layer.Visible == true)
            {
              RenderObjects(layer.Objects.ToArray(), graph, exceptObjects, useTextures, drawPoints);
            }
          }
        }

        public void RenderObjects(QObject[] qObjects, Graphics graph, List<QObject> exceptObjects, bool useTexture, bool drawPoints)
        {
          if (graph == null || qObjects.Count() == 0)
          {
            return;
          }

          for (int i = qObjects.Count(); i > 0; i--)
          {
            QObject qob = qObjects[i - 1];

            if ((exceptObjects == null) || (exceptObjects.Contains(qob) == false))
            {
              RenderObject(qob, graph, useTexture, drawPoints);
            }
          }
        }
        
        public void RenderObject(QObject qObj, Graphics graph, bool textured, bool cornerPoints)
        {
            if (graph == null || qObj == null)
            {
                return;
            }

            //TODO: Check Visibility for high performance 

            //QRectangle drawRect = GetRectOnScreen(FixRectangle(qObj.Rect));

            QPolygone drawPoly = QGraphicsHelper.GetPolyOnScreen(qObj.Poly);

            if (qObj.Poly.Points.Count > 1)
            {
              if (qObj.Visible == true)
              {
                if (textured == true)
                {
                  Image img = QGraphicsHelper.FindTexture(qObj.Texture.KeyName);

                  if (img != null)
                  {
                    Rectangle r = QGraphicsHelper.GetRectOnScreen(QGraphicsHelper.GetPolygoneRect(qObj.Poly));

                    r.X = 0;
                    r.Y = 0;

                    TextureBrush br = new TextureBrush(img, qObj.Texture.WrapMode);
                    
                    // br.ScaleTransform(QRender.ZoomAspect / QRender.Textures.OriginalImages.ImageSize.Width, QRender.ZoomAspect / QRender.Textures.ImagesList.ImageSize.Height);
                    //new Rectangle(qObj.Texture.DestinationRect.Left,
                    //   qObj.Texture.DestinationRect.Top,
                    //   qObj.Texture.DestinationRect.Width,
                    //   qObj.Texture.DestinationRect.Height));
                    
                    graph.FillPolygon(br, QGraphicsHelper.QPointsToScreenPoints(qObj.Poly.Points.ToArray()));
                  }
                  else
                  {
                      graph.FillPolygon(new SolidBrush(qObj.Color), QGraphicsHelper.QPointsToScreenPoints(qObj.Poly.Points.ToArray()));
                  }
                }
                else
                {
                    graph.FillPolygon(new SolidBrush(qObj.Color), QGraphicsHelper.QPointsToScreenPoints(qObj.Poly.Points.ToArray()));
                }
              }
              else
              {
                Pen pen = new Pen(Preferences.InvisibleObjectFrameColor);
                pen.DashStyle = DashStyle.Dot;

                graph.DrawPolygon(pen, QGraphicsHelper.QPointsToScreenPoints(qObj.Poly.Points.ToArray()));
              }
              if (cornerPoints == true)
              {
                Pen pen = new Pen(Preferences.ActiveObjectFrameColor);
                pen.Width = Preferences.FrameRectPenWidth;

                //Corner rects
                graph.DrawRectangles(pen, QGraphicsHelper.GetFrameRectsOnScreenInPoints(qObj.Poly.Points.ToArray(), Preferences.PointFrameRectWidth));
              }
            }
        }

        public void RenderPointsHints(QPolygone poly, Graphics graph)
        {
          Font font = new Font("Tahoma", Preferences.HintTextSize);
          QPoint center = QGraphicsHelper.GetPolygoneCenter(poly);
          Pen p = new Pen(Preferences.HintFrameColor);
          Brush b =  new SolidBrush(Preferences.HintBackColor);
          Brush tb = new SolidBrush(Preferences.HintTextColor);

          foreach (QPoint qp in poly.Points)
          {
            string text = String.Format("{0}:{1}", qp.X.ToString(), qp.Y.ToString());
            QPoint sp = QGraphicsHelper.GetPointOnScreen(qp);
            SizeF size = graph.MeasureString(text, font);

            sp.X += (qp.X < center.X ? -size.Width : 5);
            sp.Y += (qp.Y < center.Y ? 5 : -size.Height);

            Rectangle r = new Rectangle((int)sp.X, (int)sp.Y, (int)size.Width, (int)size.Height);

            graph.DrawRectangle(p, r);
            r.X += 1;
            r.Y += 1;
            r.Width -= 1;
            r.Height -= 1;
            graph.FillRectangle(b, r);
            graph.DrawString(text, font, tb, sp.X, sp.Y);
          }
        }

        public void RenderRectPoints(QPoint[] points, Graphics graph, Color color)
        {
          if (points.Length > 0)
          {
            Pen pen = new Pen(color);
            pen.Width = Preferences.FrameRectPenWidth;

            //Corner rects
            graph.DrawRectangles(pen, QGraphicsHelper.GetFrameRectsOnScreenInPoints(points, Preferences.PointFrameRectWidth));
          }
        }

        public  void RenderActiveObject(QObject qObj, Graphics graph, bool asEnabled)
        {
          if (graph == null || qObj == null)
          {
            return;
          }

          //RenderObject(qObj, graph, true);

          HatchBrush hb;

          if (asEnabled == true)
          {
            hb = new HatchBrush(HatchStyle.SmallCheckerBoard, qObj.Color, Color.Transparent);
          }
          else
          {
            hb = new HatchBrush(HatchStyle.Percent30, Preferences.DisabledObjectColor, Color.Transparent);
          }

          Pen pen = new Pen(Preferences.ActiveObjectFrameColor);
          pen.Width = Preferences.FrameRectPenWidth;

          if (qObj.Poly.Points.Count > 0)
          {
            PointF[] drawPoly = QGraphicsHelper.QPointsToScreenPoints(qObj.Poly.Points.ToArray());
            graph.FillPolygon(hb, drawPoly);
            graph.DrawPolygon(pen, drawPoly);
            //Corner rects

            graph.DrawRectangles(pen, QGraphicsHelper.GetFrameRectsInPoints(drawPoly, Preferences.PointFrameRectWidth));
          }
          //center
          QPoint center = QGraphicsHelper.GetPolygoneCenter(qObj.Poly);
          QPoint cp = QGraphicsHelper.GetPointOnScreen(center);

          graph.DrawLine(pen, cp.X, cp.Y - Preferences.ObjectCenterCrossSize, cp.X, cp.Y + Preferences.ObjectCenterCrossSize);
          graph.DrawLine(pen, cp.X - Preferences.ObjectCenterCrossSize, cp.Y, cp.X + Preferences.ObjectCenterCrossSize, cp.Y);
          //object rect
          if (Preferences.ShowObjectRect == true)
          {
              graph.DrawRectangle(new Pen(Preferences.ActiveObjectFrameColor), QGraphicsHelper.GetRectOnScreen(QGraphicsHelper.GetPolygoneRect(qObj.Poly)));
          }
        }

        public void RenderLineOnScreen(QPoint qp1, QPoint qp2, Graphics graph, Color color, int lineWidth)
        {
            QPoint sp1 = QGraphicsHelper.GetPointOnScreen(qp1);
            QPoint sp2 = QGraphicsHelper.GetPointOnScreen(qp2);

            RenderLine(sp1, sp2, graph, color, lineWidth);
        }
        public void RenderLine(QPoint qp1, QPoint qp2, Graphics graph, Color color, int lineWidth)
        {
          Pen pen = new Pen(color);
          pen.Width = lineWidth;
          graph.DrawLine(pen, qp1.X, qp1.Y, qp2.X, qp2.Y);
        }
        public void RenderAxes(Graphics graph)
        {
            QPoint qpX1 = new QPoint() { X = 0, Y = ViewRect.Top};
            QPoint qpX2 = new QPoint() { X = 0, Y = ViewRect.Top + ViewRect.Height };
            QPoint qpY1 = new QPoint() { Y = 0, X = ViewRect.Left};
            QPoint qpY2 = new QPoint() { Y = 0, X = ViewRect.Left + ViewRect.Width };

            if (QGraphicsHelper.IsPointInRect(qpX1.X, qpX2.Y, ViewRect) == true ||
                QGraphicsHelper.IsPointInRect(qpX2.X, qpX2.Y, ViewRect) == true ||
                QGraphicsHelper.IsPointInRect(qpY1.X, qpY1.Y, ViewRect) == true ||
                QGraphicsHelper.IsPointInRect(qpY2.X, qpY2.Y, ViewRect) == true)
            {
                if (Preferences.TopOnBottom == false) //some stupid thing
                {
                    qpX1.Y = -qpX1.Y;
                    qpX2.Y = -qpX2.Y;
                    qpY2.Y = -qpY2.Y;
                    qpY2.Y = -qpY2.Y;
                }

                RenderLineOnScreen(qpX1, qpX2, graph, Preferences.AxisColor, 1);
                RenderLineOnScreen(qpY1, qpY2, graph, Preferences.AxisColor, 1);
            }
        }

        public void RenderGrid(Graphics graph, float step)
        {
          QRectangleF rect = QGraphicsHelper.NewQRectF(ViewRect);
          float it = rect.Width / step;
          float start = rect.Left - (rect.Left % step);

          for (int i = 0; i < it; i++)
          {
            QPoint qp1 = new QPoint() { X = start + (i * step), Y = rect.Top };
            QPoint qp2 = new QPoint() { X = start + (i * step), Y = rect.Top + rect.Height };

            if (Preferences.TopOnBottom == false)
            {
              qp1.Y = -qp1.Y;
              qp2.Y = -qp2.Y;
            }

            qp1 = QGraphicsHelper.GetPointOnScreen(qp1);
            qp2 = QGraphicsHelper.GetPointOnScreen(qp2);

            RenderLine(qp1, qp2, graph, Preferences.GridColor, 1);
          }

          it = ViewRect.Height / step;
          start = ViewRect.Top - (rect.Top % step);
          
          for (int i = 0; i < it; i++)
          {
            QPoint qp1 = new QPoint() { Y = start + (i * step), X = rect.Left };
            QPoint qp2 = new QPoint() { Y = start + (i * step), X = rect.Left + rect.Width };

            if (Preferences.TopOnBottom == false)
            {
              qp1.Y = -qp1.Y;
              qp2.Y = -qp2.Y;
            }

            qp1 = QGraphicsHelper.GetPointOnScreen(qp1);
            qp2 = QGraphicsHelper.GetPointOnScreen(qp2);

            RenderLine(qp1, qp2, graph, Preferences.GridColor, 1);
          }
        }
    }
}
